package com.wufeng.mycode;

import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicStampedReference;

class User {
    String name;
    int age;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

/**
 * CAS缺点：1、循环时间长开销大
 * 2、只能保证一个共享变量的原子操作
 * 3、ABA问题
 * <p>
 * ABA问题：加入两个线程同时拿到了主内存的值A,线程T1被挂起，线程T2更新主内存的值为B，然后T1还在挂起中，
 * 线程T2有进行了更新，把主内存的值修改为A,这之后T1执行操作，比较的时候工作内存值为A，主内存的值也是A，
 * 但是主内存的值已经发生了变化，A->B->A。
 * 线程T1操作是成功的，但是不代表这个过程就是没有问题的。
 * <p>
 * AtomicReference<T> 泛型把类封装成原子类。
 */
public class ABA {
    public static void main(String[] args) {
        User z3 = new User("zhangsan", 22);
        User li4 = new User("lisi", 18);
        AtomicReference<User> atomicReference = new AtomicReference<>();
        atomicReference.set(z3);
        System.out.println(atomicReference.compareAndSet(z3, li4) + "\t" + atomicReference.get().toString());
        System.out.println(atomicReference.compareAndSet(z3, li4) + "\t" + atomicReference.get().toString());
        System.out.println("======以下是 ABA操作的产生。=======");

        AtomicReference<Integer> atomicInteger = new AtomicReference<>(100);
        new Thread(() -> {
            atomicInteger.compareAndSet(100, 101);
            System.out.println(Thread.currentThread().getName() + "\t 现在的值为:" + atomicInteger.get());
            atomicInteger.compareAndSet(101, 100);
        }, "t1").start();
        new Thread(() -> {
            // 暂停一秒钟，保证线程T1一定完成ABA过程
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "\t" + atomicInteger.compareAndSet(100, 2020) + "\t" + atomicInteger.get());
        }, "t2").start();

        System.out.println("=========解决ABA问题=========");
        AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1);
        new Thread(() -> {
            atomicStampedReference.compareAndSet(100, 101, 1, 2);
            atomicStampedReference.compareAndSet(101, 100, 2, 3);
        }, "t3").start();
        new Thread(() -> {
            System.out.println(atomicStampedReference.compareAndSet(100, 2020, 1, 2));
        }, "t4").start();
    }
}
